package xmlparser.dreamcoder.com.asimplexmlparser;

import android.util.Xml;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * Description:XML's parser
 * User: Dream_Coder(chenchen_839@126.com)
 * Date: 2015-08-31
 * Time: 23:32
 */
public class ASimpleXMLParser<T> {

    private List<T> res;
    private Class<T> clz;
    private File xmlFile;
    private String xmlString;
    private String doucmentTag;
    private XmlPullParser parser;
    private InputStream xmlStream;
    private List<String> fieldsList;

    /**
     * 可以通过三种方式解析xml文件，分别为字符串、文件、流
     * @param xmlString
     */
    public ASimpleXMLParser(String xmlString,Class<T> clz) {
        this.xmlString = xmlString;
        this.clz = clz;
        initParser();
    }
    public ASimpleXMLParser(File xmlFile,Class<T> clz) {
        this.xmlFile = xmlFile;
        this.clz = clz;
        initParser();
    }
    public ASimpleXMLParser(InputStream xmlStream,Class<T> clz) {
        this.xmlStream = xmlStream;
        this.clz = clz;
        initParser();
    }

    /**
     * 初始化数据
     */
    public void init() {
        xmlString = null;
        xmlFile = null;
        //默认情况下，文档的根标签为bean的类型小写形式,可以通过setDocumentTag(String)更改
        doucmentTag = clz.getSimpleName().toLowerCase();
    }


    /**
     * 初始化xmlparser
     * @throws XmlPullParserException FileNotFoundException
     */
    private void initParser() {
        parser = Xml.newPullParser();
        try {
            if(xmlString != null) {
                parser.setInput(new StringReader(xmlString));
            }else if(xmlFile != null) {
                parser.setInput(new FileReader(xmlFile));
            }else {
                parser.setInput(xmlStream,"UTF-8");
            }
        } catch (XmlPullParserException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * 通过反射获取bean的属性值
     */
    public void beanFieldToList(){
        fieldsList = new ArrayList<String>();
        Field[] fields = clz.getDeclaredFields();
        Field.setAccessible(fields,true);
        for (Field field : fields) {
            fieldsList.add(field.getName());
        }

    }

    /**
     * 设置文档的根标签,默认为bean的类型
     * NOTE:默认情况下为bean的小写形式
     */
    public void setDoucmentTag(String tag) {
        this.doucmentTag = tag;
    }
    /**
     * 将数据解析为bean 并传出
     * @param
     * @return
     */
    public List<T> execute() {
        init();
        beanFieldToList();
        T obj = null;
        int i = 0;
        boolean flag = false;
        if(fieldsList.size() <= 0) {
            return null;
        }else {
            try {
                int type = parser.getEventType();
                while (type != XmlPullParser.END_DOCUMENT) {
                    switch (type) {
                        case XmlPullParser.START_DOCUMENT :
                            res = new ArrayList<T>();break;
                        case XmlPullParser.START_TAG:
                            String tagName = parser.getName();
                            if(tagName.equals(doucmentTag)) {
                                obj = clz.newInstance();
                                flag = true;
                            }else {
                                if (fieldsList.contains(tagName)) {
                                    Method method = clz.getMethod(generateSetMethod(tagName),
                                    new Class[]{String.class});
                                    method.invoke(obj, new Object[]{parser.nextText()});
                                }
                            }
                            break;
                        case XmlPullParser.END_TAG:
                            if(doucmentTag.equals(parser.getName())) {
                                flag = false; res.add(obj);
                            }
                            break;
                    }
                    type = parser.next();
                }
            } catch (XmlPullParserException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return res;
        }
    }

    /**
     * 将方法名的第一个字母转换成大写，目的是为了拼接set方法
     * @param method
     * @return
     */
    public String toMethodUpper(String method) {
        char[] chars = method.toCharArray();
        chars[0] = Character.toUpperCase(chars[0]);
        return new String(chars);
    }
    /**
     * 获取set方法名称
     * @param method
     * @return
     */
    public String generateSetMethod(String method) {
        String methods = toMethodUpper(method);
        return "set"+methods;
    }

}
